//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-01-01
// Contains ...
namespace LargoEditor.Abstract {
using LargoBase.Abstract;
using LargoBase.Enums;
using LargoBase.Localization;
using LargoBase.Midi;
using LargoBase.Music;
using LargoKernel;
using LargoKernel.Blocks;
using LargoKernel.Board;
using LargoKernel.Composer;
using LargoKernel.Patterns;
using LargoModels;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;
using System.Linq;
///
/// Musical Editor.
///
public sealed class BlockEditor {
#region Fields
//// Prepared for the future
///
/// Max Editor Lines.
///
//// private const int MaxEditorLines = 250;
///
/// Max Editor Bars.
///
//// private const int MaxEditorBars = 2500;
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
public BlockEditor() {
this.MusicalSelection = new MusicalSelection();
this.EditorContent = EditorContent.NumberOfTones;
this.EditorColor = EditorColor.RhythmicDensity;
}
#endregion
#region Public static properties
///
/// Gets or sets the lastly edited musical block.
///
/// Property description.
public static MusicalBlock LastlyEditedMusicalBlock { get; set; }
///
/// Gets or sets the lastly edited block model.
///
/// Property description.
public static BlockModel LastlyEditedBlockModel { get; set; }
#endregion
#region Public properties (Editor selection)
///
/// Gets or sets Largo File Path.
///
///
/// Property description.
///
public string LargoFilePath { get; set; }
///
/// Gets or sets a value indicating whether this instance has changes.
///
///
/// true if this instance has changes; otherwise, false.
///
public bool HasChanges { get; set; }
///
/// Gets a value indicating whether selection.
///
/// Property description.
public bool HasSelection => MusicalSelection?.Points != null && this.MusicalSelection.Points.Any();
///
/// Gets the selection.
///
/// Property description.
public MusicalSelection MusicalSelection { get; }
///
/// Gets the selected elements.
///
/// Property description.
public IList SelectedElements
{
get
{
if (!this.HasSelection) {
return null;
}
var list = new List();
list.AddRange(this.Block.Body.GetSelectedElements(this.MusicalSelection));
return list;
}
}
#endregion
#region Public Properties
///
/// Gets or sets Musical Block Model.
///
///
/// Property description.
///
public MusicalBlock Block { get; set; }
///
/// Gets or sets Musical Block Model.
///
///
/// Property description.
///
public BlockModel BlockModel { get; set; }
///
/// Gets the name of the block model.
///
///
/// The name of the block model.
///
/// Not Implemented
public string BlockModelName
{
get
{
if (this.BlockModel != null) {
return this.BlockModel.FileAndName; //// givenBlock.FullName;
}
return string.Empty;
}
}
///
/// Gets the display name.
///
///
/// The display name.
///
/// Not Implemented Exception
public string DisplayName
{
get
{
if (this.Block != null) {
return this.Block.NumberNameAndLength;
}
if (this.BlockModel != null) {
return this.BlockModel.NumberNameAndLength;
}
return string.Empty;
}
}
///
/// Gets or sets the content of the editor.
///
///
/// The content of the editor.
///
public EditorContent EditorContent { get; set; }
///
/// Gets or sets the color of the editor.
///
///
/// The color of the editor.
///
public EditorColor EditorColor { get; set; }
///
/// Gets or sets the name.
///
///
/// The name of edited document.
///
public string Name { get; set; }
///
/// Gets or sets the description.
///
///
/// The description.
///
public string Description { get; set; }
///
/// Gets or sets a value indicating whether [play on click].
///
///
/// True if [play on click]; otherwise, false.
///
public bool PlayOnClick { get; set; }
///
/// Gets or sets a value indicating whether [synchronize motives].
///
///
/// true if [synchronize motives]; otherwise, false.
///
public bool SynchronizeMotives { get; set; }
///
/// Gets or sets a value indicating whether [hide mute tracks].
///
///
/// true if [hide mute tracks]; otherwise, false.
///
public bool HideMuteTracks { get; set; }
///
/// Gets the fixed tracks.
///
/// Returns value.
public IList GetFixedTracks
{
get
{
List tracks = new List();
for (byte lineIndex = 0; lineIndex < this.Block.Header.NumberOfTracks; lineIndex++) {
var track = this.GetTrack(lineIndex);
if (track != null && track.Status.Purpose == TrackPurpose.Fixed) { //// track.HasTemplate
tracks.Add(track);
}
}
return tracks;
}
}
///
/// Gets all tracks for composition.
///
/// Returns value.
public IList GetAllTracksForComposition
{
get
{
List tracks = new List();
//// if (composeAll) { mblock.LoadTracksFromModel(blockModel); return; }
for (byte lineIndex = 0; lineIndex < this.Block.Header.NumberOfTracks; lineIndex++) {
var track = this.GetTrack(lineIndex);
if (track == null || track.Status.Purpose == TrackPurpose.Mute || track.Status.Purpose == TrackPurpose.None) {
continue;
}
//// (composeAllTracks && eline.IsImported)
if (track.Status.Purpose == TrackPurpose.Fixed) {
//// Add original imported track
tracks.Add(track);
}
// ReSharper disable once InvertIf
if (track.Status.Purpose == TrackPurpose.Composed) {
track.Reset();
track.Status.MelodicVariety = new MusicalVariety(MusicalSetup.Singleton);
//// 2016/10 newtrack.Status.PlannedTones = new MusicalToneCollection();
//// track.Status.HarmonicModalization = MusicalSetup.Singleton.HarmonicModalization;
//// LineType = MusicalLineType.Melodic,
//// Purpose = TrackPurpose.Composed,
//// Channel = track.Channel
//// 2016 if (eline.Channel != null) { newtrack.Status.Channel = (MidiChannel)eline.Channel; }
tracks.Add(track);
}
}
return tracks;
}
}
#endregion
#region Private properties
#endregion
#region Factory methods
#endregion
#region Public methods - Loader
///
/// Loads the block.
///
/// The given block.
public void LoadBlock(MusicalBlock givenBlock) {
Contract.Requires(givenBlock != null);
//// && givenBlock.Strip == null
if (givenBlock.Body == null)
{
return;
}
this.Name = this.BlockModelName;
this.Block = givenBlock;
BlockEditor.LastlyEditedMusicalBlock = givenBlock;
//// this.LoadTracks(this.Block.Strip);
//// this.LoadBars(this.Block.Body);
if (this.Block.ContainsMusic) {
this.Block.Body.SetStatusFromMusic();
}
this.Block.Body.DetermineOriginalElements();
BlockEditor.LastlyEditedBlockModel = this.BlockModel;
}
#endregion
#region Public methods - Composition
///
/// Composes the music.
///
/// Returns value.
public MusicalBundle ComposeMusic() {
var currentBlock = this.Block; //// blockModel.SourceMusicalBlock
var mheader = (MusicalHeader)currentBlock.Header.Clone();
MusicalContext context = new MusicalContext(MusicalSetup.Singleton, mheader);
var composedBlock = new MusicalBlock {
//// Number = currentBlock.Number,
Header = mheader,
Strip = new MusicalStrip(context)
};
ProcessLogger.Singleton.SendLogEvent(currentBlock.Header.Name, LocalizedMusic.String("Initialization..."), 0);
var tracks = this.GetAllTracksForComposition; //// GetAllTracks(false);
composedBlock.Strip.SetTracks(tracks);
composedBlock.Header.NumberOfTracks = tracks.Count;
composedBlock.ConvertStripToBody(true);
//// Have to be --- set status from editor !!!!!!!!!!
//// 2016/03 !!!!!!!!!!!!!
//// var blockModel = this.Block.ExtractMusicalBlockModel();
///// composedBlock.SetMusicalStatus(blockModel);
var blockStatus = new BlockStatus(currentBlock);
composedBlock.SetBlockStatus(blockStatus);
//// TEMPO 2017/01 ?!? //// composedBlock.SetTempoEvents(blockModel.BlockChanges.TempoChanges);
var tevents = new List();
int deltatime = 0;
var h = composedBlock.Header;
var barmididuration = MusicalProperties.BarMidiDuration(h.System.RhythmicOrder, h.Metric.MetricBeat, h.Metric.MetricGround, h.Division);
foreach (var bar in composedBlock.Body.Bars) {
if (bar.Status.TempoNumber > 0) {
var tevent = new MetaTempo(0, 100) {
StartTime = deltatime,
Tempo = bar.Status.TempoNumber
};
tevents.Add(tevent);
deltatime += barmididuration;
}
}
if (tevents.Count > 0) {
composedBlock.Body.TempoEvents = tevents; //// !?!?!? do not work
}
//// Main compositional method.
composedBlock.Body.ComposeMusic();
ProcessLogger.Singleton.SendLogEvent(currentBlock.Header.Name, LocalizedMusic.String("Finalization..."), 0);
composedBlock.Strip.WriteBody(composedBlock.Body);
composedBlock.Strip.CorrectOctaves();
var filename = currentBlock.FullName;
int variant = 0;
while (File.Exists(filename)) {
variant++;
filename = currentBlock.FullName + variant.ToString();
}
var composedFile = MusicalBundle.GetEnvelopeOfBlock(composedBlock, filename);
return composedFile;
}
#endregion
///
/// Shifts the line octaves.
///
/// The number of octaves.
public void ShiftOctavesInSelection(int numberOfOctaves) { //// int lineIndex,
///// var elements = this.BlockEditor.SelectedLineElements(eline.LineIndex);
var elements = this.SelectedElements;
//// var elements = this.SelectedLineElements(lineIndex);
//// var elements = this.ElementsOfLine(lineIndex);
if (elements == null) {
return;
}
foreach (var element in elements.Where(element => element != null)) {
element.ShiftOctave(numberOfOctaves);
}
}
///
/// Selected line elements.
///
/// Index of the given line.
/// Returns value.
public IList SelectedLineElements(int givenLineIndex) {
if (!this.HasSelection) {
return null;
}
var list = new List();
list.AddRange(this.Block.Body.GetSelectedElements(this.MusicalSelection, givenLineIndex));
return list;
}
#region Orchestration
///
/// Orchestrate By Model.
///
/// The given style.
public void OrchestrateBy(MusicalOrchestration givenStyle) {
if (givenStyle == null || this.Block == null) {
return;
}
this.Block.Orchestration = new MusicalOrchestration(this.Block);
givenStyle.OrchestrateMusicalBlock(this.Block);
}
#endregion
#region Tracks
///
/// Gets all tracks.
///
/// if set to true [include tones].
/// Returns value.
public IList GetAllTracks(bool includeTones) {
List tracks = new List();
for (byte lineIndex = 0; lineIndex < this.Block.Header.NumberOfTracks; lineIndex++) {
var track = this.GetTrack(lineIndex);
if (track != null) {
var rtrack = includeTones ? track : track.Clone(false);
rtrack.Status.MelodicVariety = new MusicalVariety(MusicalSetup.Singleton);
//// 2016/10 rtrack.Status.PlannedTones = new MusicalToneCollection();
tracks.Add(rtrack);
}
}
return tracks;
}
#endregion
#region Get bars and lines
///
/// Gets the bar.
///
/// The given bar number.
/// Returns value.
public MusicalBar GetBar(int givenBarNumber) {
return this.Block.Body.GetBar(givenBarNumber);
}
///
/// Gets the line.
///
/// Index of the given line.
///
/// Returns value.
///
public MusicalTrack GetTrack(int givenLineIndex) {
var track = this.Block.Strip.GetTrack(givenLineIndex);
return track;
}
#endregion
#region Rhythmic
///
/// Rhythmic of harmony.
///
/// Returns value.
[UsedImplicitly]
public IList RhythmicOfHarmony() {
var structs = new List();
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var bar1 in this.Block.Body.Bars.Where(bar1 => bar1 != null)) {
if (bar1.Status.HarmonicBar == null) {
continue;
}
var rstr = bar1.Status.HarmonicBar.RhythmicStructure; //// Clone?
structs.Add(rstr);
}
return structs;
}
///
/// Reorders the line rhythmic.
///
/// The line number.
/// The block model.
public void SetRandomRhythm(int lineIndex, BlockModel blockModel) {
Contract.Requires(blockModel != null);
var elements = this.Block.Body.ElementsOfLine(lineIndex);
var master = new ElementMaster(elements);
var rstructures = blockModel.Core.RhythmicCore.RhythmicStructuresOfMotives;
master.SetRandomRhythm(rstructures);
}
#endregion
#region Reorder line properties
///
/// Reorders the line rhythmic.
///
/// The line number.
public void ReorderLineRhythmic(int lineIndex) {
var elements = this.Block.Body.ElementsOfLine(lineIndex);
var master = new ElementMaster(elements);
master.ReorderRhythmic();
}
///
/// Reorders the line rhythmic.
///
/// The line number.
public void ReorderLineMelodic(int lineIndex) {
var elements = this.Block.Body.ElementsOfLine(lineIndex);
//// var musicalEditorElements = elements as IList ?? elements.ToList();
var master = new ElementMaster(elements);
master.ReorderMelodic();
}
///
/// Reorders the line rhythmic.
///
public void ReorderLineHarmonic() {
foreach (var bar1 in this.Block.Body.Bars) {
if (bar1?.Status.HarmonicBar == null) {
continue;
}
var bar1c = bar1;
foreach (var bar2 in this.Block.Body.Bars.Where(bar2 => bar2.Status.HarmonicBar != null && bar2.BarNumber > bar1c.BarNumber).Where(bar2 => MathSupport.RandomNatural(10) < 3)) {
bar1.SwapHarmonyWith(bar2);
}
}
}
#endregion
}
}